use std::cell::RefCell;
use std::rc::Rc;

struct te_variable {
    name: String,
    type_: i32,
}

struct state {
    lookup: Vec<te_variable>,
    lookup_len: usize,
}

pub struct TeExpr {
    pub type_: i32,
    pub value: f64,
    pub bound: Option<Vec<f64>>,
    pub function: Option<fn(Vec<f64>) -> f64>,
    pub parameters: Vec<Rc<RefCell<TeExpr>>>,
}

pub struct State {
    pub start: String,
    pub next: String,
    pub type_: i32,
    pub value: f64,
    pub bound: Option<Vec<f64>>,
    pub function: Option<fn(Vec<f64>) -> f64>,
    pub context: Option<Rc<RefCell<State>>>,
    pub lookup: Vec<te_variable>,
    pub lookup_len: usize,
}

const TOK_NULL: i32 = 0;
const TOK_END: i32 = 1;
const TOK_NUMBER: i32 = 2;
const TOK_ERROR: i32 = 3;
const TOK_VARIABLE: i32 = 4;
const TOK_INFIX: i32 = 5;
const TOK_OPEN: i32 = 6;
const TOK_CLOSE: i32 = 7;
const TOK_SEP: i32 = 8;

const TE_VARIABLE: i32 = 0;
const TE_CLOSURE0: i32 = 1;
const TE_CLOSURE1: i32 = 2;
const TE_CLOSURE2: i32 = 3;
const TE_CLOSURE3: i32 = 4;
const TE_CLOSURE4: i32 = 5;
const TE_CLOSURE5: i32 = 6;
const TE_CLOSURE6: i32 = 7;
const TE_CLOSURE7: i32 = 8;
const TE_FUNCTION0: i32 = 9;
const TE_FUNCTION1: i32 = 10;
const TE_FUNCTION2: i32 = 11;
const TE_FUNCTION3: i32 = 12;
const TE_FUNCTION4: i32 = 13;
const TE_FUNCTION5: i32 = 14;
const TE_FUNCTION6: i32 = 15;
const TE_FUNCTION7: i32 = 16;

pub fn divide(a: f64, b: f64) -> f64 {
    // 注意：该函数不允许修改，因为工程中其他文件中的函数也调用了他们，如果修改了，会影响其他文件内函数的功能，完整原样返回该函数
    a / b
}

pub fn sub(a: f64, b: f64) -> f64 {
    a - b
}
// 注意：该函数不允许修改，因为工程中其他文件中的函数也调用了他们，如果修改了，会影响其他文件内函数的功能，完整原样返回该函数

pub fn add(a: f64, b: f64) -> f64 {
    a + b
}
// 注意：该函数不允许修改，因为工程中其他文件中的函数也调用了他们，如果修改了，会影响其他文件内函数的功能，完整原样返回该函数

pub fn find_builtin(name: String, len: i32, functions: &[te_variable]) -> Option<&te_variable> {
    let mut imin = 0;
    let mut imax = functions.len() - 2;

    while imax >= imin {
        let i = imin + ((imax - imin) / 2);
        let c = name
            .as_bytes()
            .iter()
            .zip(functions[i].name.as_bytes())
            .take(len as usize)
            .fold(0, |acc, (a, b)| acc + (*a as i32 - *b as i32));
        let c = if c == 0 {
            -(functions[i].name.as_bytes()[len as usize] as i32)
        } else {
            c
        };
        if c == 0 {
            return Some(&functions[i]);
        } else if c > 0 {
            imin = i + 1;
        } else {
            imax = i - 1;
        }
    }

    None
}

pub fn find_lookup<'a>(s: &'a State, name: &str, len: usize) -> Option<&'a te_variable> {
    if s.lookup.is_empty() {
        return None;
    }

    for var in s.lookup.iter().take(s.lookup_len) {
        if var.name.len() == len && var.name == name {
            return Some(var);
        }
    }
    None
}

pub fn mul(a: f64, b: f64) -> f64 {
    // 注意：该函数不允许修改，因为工程中其他文件中的函数也调用了他们，如果修改了，会影响其他文件内函数的功能，完整原样返回该函数
    a * b
}

pub fn te_free_parameters(n: Option<Rc<RefCell<TeExpr>>>) {
    if n.is_none() {
        return;
    }
    let n = n.unwrap();
    let type_mask = n.borrow().type_ & 0x0000001F;
    match type_mask {
        7 | 23 => te_free(Some(n.borrow().parameters[6].clone())),
        6 | 22 => te_free(Some(n.borrow().parameters[5].clone())),
        5 | 21 => te_free(Some(n.borrow().parameters[4].clone())),
        4 | 20 => te_free(Some(n.borrow().parameters[3].clone())),
        3 | 19 => te_free(Some(n.borrow().parameters[2].clone())),
        2 | 18 => te_free(Some(n.borrow().parameters[1].clone())),
        1 | 17 => te_free(Some(n.borrow().parameters[0].clone())),
        _ => (),
    }
}

pub fn te_free(n: Option<Rc<RefCell<TeExpr>>>) {
    if n.is_none() {
        return;
    }
    let n = n.unwrap();
    te_free_parameters(Some(n.clone()));
}

pub fn negate(a: f64) -> f64 {
    -a
}
// 注意：该函数不允许修改，因为工程中其他文件中的函数也调用了他们，如果修改了，会影响其他文件内函数的功能，完整原样返回该函数
